/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ScannerParser;

import java.util.*;

/**
 *
 * @author jefoutta
 */
public class SymbolTable {

    public static SymbolTable actualSymbolTable;
    public static LinkedList<Symbol> pending = new LinkedList();
    public static LinkedList<SymbolTable> pendingChild = new LinkedList();
    private LinkedList<Symbol> symbolList;
    private LinkedList<SymbolTable> children;
    private SymbolTable parent;
    public String name;
    private int width;
    private int numberOfTemporals;
    private LinkedList<Temporal> temporals = new LinkedList();
    private int numberOfParam;
    private int paramWidth;

    public SymbolTable(){
        this.parent = null;
        this.symbolList = new LinkedList();
        this.children = new LinkedList();
        this.width = 0;
        this.paramWidth = 0;
        this.numberOfTemporals = 0;
        SymbolTable.actualSymbolTable = this;
    }

    public SymbolTable(SymbolTable tparent){
        this.parent = tparent;
        this.symbolList = new LinkedList();
        this.children = new LinkedList();
        this.width = 0;
        this.paramWidth = 0;
        this.numberOfTemporals = 0;
    }

    public void addChildSymbolTable(int option, String name){
        switch(option){
            case 0:{//this case is when the symbol is variable
                this.children.addLast(null);

            }break;
            case 1:{//this case is when the symbol is struct
                this.children.addLast(new SymbolTable(this));
                SymbolTable.actualSymbolTable = this.children.getLast();
                SymbolTable.actualSymbolTable.name = name+"_ST";
            }break;
            case 2:{//this case is when the symbol is a method
                this.children.addLast(new SymbolTable(this));
                SymbolTable.actualSymbolTable = this.children.getLast();
                SymbolTable.actualSymbolTable.name = name+"_ST";
            }break;
        }
    }

    public void moveToChildSymbolTable(String tname){
        String ttype = tname.split(" ")[0];
        String ttname = tname.split(" ")[1];
        if(ttype.equals("method")){
            for(int i = 0; i < this.symbolList.size(); i++){
                if((this.symbolList.get(i).getName().equals(ttname))&&(this.symbolList.get(i).getSymbolType().equals(ttype))){
                    if(!this.symbolList.get(i).alreadyTaken){
                        this.symbolList.get(i).alreadyTaken = true;
                        SymbolTable.actualSymbolTable =  this.children.get(i);
                        break;
                    }
                }
            }
        }else{
            for(int i = 0; i < this.symbolList.size(); i++){
                if((this.symbolList.get(i).getName().equals(ttname))&&(this.symbolList.get(i).getSymbolType().equals(ttype)))
                    SymbolTable.actualSymbolTable =  this.children.get(i);
            }
        }

    }

    public void returnToParent(){
        SymbolTable.actualSymbolTable = this.parent;
    }

    public void addSymbol(Symbol symbol){
        this.symbolList.add(symbol);
    }

    public void setName(String tname){
        name = tname;
    }

    public void setNumberOfParam(int num){
        numberOfParam = num;
    }

    public void addWidth(int twidth){
        this.width = this.width+twidth;
    }

    public void addParamWidth(int twidth){
        this.paramWidth = this.paramWidth + twidth;
    }

    public void addTemporal(Temporal temp){
        this.temporals.add(temp);
        this.numberOfTemporals++;
    }

    public boolean containsTemporal(Temporal temp){
        if(this.temporals.contains(temp))
            return true;
        else
            return false;
    }

    public int getIndexOfTemporal(Temporal temp){
        return this.temporals.indexOf(temp);
    }

    public Symbol getSymbol(String tname){
        String ttype;
        String ttname;
        if(!tname.startsWith("method ")){
                ttype = tname.split(" ")[0];
                ttname = tname.split(" ")[1];
                for(int i = 0; i < this.symbolList.size(); i++){
                    if((this.symbolList.get(i).getName().equals(ttname))&&(this.symbolList.get(i).getSymbolType().equals(ttype)))
                        return this.symbolList.get(i);
                }
                if(this.parent != null){
                    return this.parent.getSymbol(tname);
                }
                return null;
        }else{
            ttype = tname.split(" ")[0];
            ttname = tname.replaceFirst(ttype+" ", "");
            for(int i = 0; i < this.symbolList.size(); i++){
                    if((this.symbolList.get(i).getFirm().equals(ttname))&&(this.symbolList.get(i).getSymbolType().equals(ttype)))
                        return this.symbolList.get(i);
            }
            return null;
        }
    }

    public SymbolTable getChild(String tname){
        String ttype = tname.split(" ")[0];
        String ttname = tname.split(" ")[1];
        for(int i = 0; i < this.symbolList.size(); i++){
            if((this.symbolList.get(i).getName().equals(ttname))&&(this.symbolList.get(i).getSymbolType().equals(ttype)))
                return this.children.get(i);
        }
        return null;
    }

    public SymbolTable getChild(int index){
        return this.children.get(index);
    }

    public SymbolTable getLastChild(){
        return this.children.getLast();
    }

    public SymbolTable getChildRecursive(String tname){
        String ttype = tname.split(" ")[0];
        String ttname = tname.split(" ")[1];
        for(int i = 0; i < this.symbolList.size(); i++){
            if((this.symbolList.get(i).getName().equals(ttname))&&(this.symbolList.get(i).getSymbolType().equals(ttype))){
                return this.children.get(i);
            }
        }
        if(this.parent != null){
                return this.parent.getChildRecursive(tname);
        }
        return null;
    }

    public Symbol getSymbolOnlyInActualSymbolTable(String tname){
        String ttype = tname.split(" ")[0];
        String ttname = tname.split(" ")[1];
        for(int i = 0; i < this.symbolList.size(); i++){
            if((this.symbolList.get(i).getName().equals(ttname))&&(this.symbolList.get(i).getSymbolType().equals(ttype)))
                return this.symbolList.get(i);
        }
        return null;
    }

    public boolean isAlreadyDefined(String tname){
        String ttype = tname.split(" ")[0];
        String ttname = tname.split(" ")[1];
        for(int i = 0; i < this.symbolList.size(); i++){
            if((this.symbolList.get(i).getName().equals(ttname))&&(this.symbolList.get(i).getSymbolType().equals(ttype)))
                return true;
        }
        return false;
    }

    public boolean isMoreThanOnes(String tname){
        String ttype = tname.split(" ")[0];
        String ttname = tname.split("method ")[1];
        int count = 0;
        for(int i = 0; i < this.symbolList.size(); i++){
            if((this.symbolList.get(i).getFirm().equals(ttname))&&(this.symbolList.get(i).getSymbolType().equals(ttype))){
                count++;
                if(count > 1)
                    return true;
            }
        }
        return false;
    }

    public Symbol getMethodSymbol(String tname){
        String ttype = tname.split(" ")[0];
        String ttname = tname.split("method ")[1];
        int count = 0;
        for(int i = 0; i < this.symbolList.size(); i++){
            if((this.symbolList.get(i).getFirm().equals(ttname))&&(this.symbolList.get(i).getSymbolType().equals(ttype))){
                return this.symbolList.get(i);
            }
        }
        return null;
    }

    public Symbol getLastSymbol(){
        return symbolList.getLast();
    }

    public SymbolTable getParent(){
        return this.parent;
    }

    public LinkedList<Symbol> getSymbolList(){
        return this.symbolList;
    }

    public int getNumberOfTemporals(){
        return this.numberOfTemporals;
    }

    public boolean validate(){
        if(this.isAlreadyDefined("method main"))
            return true;
        return false;
    }

    public String getName(){
        return name;
    }

    public int getWidth(){
        return width;
    }

    public int getTotalWidth(){
        return width + (numberOfTemporals*2) - paramWidth;
    }

    public int getParamNumber(){
        return paramWidth / 2;
    }

    public String toString(){
        String display = "";
        for(int i = 0 ; i < symbolList.size(); i++){
            display = display + (symbolList.get(i)+" {"+children.get(i)+"}\n");
        }
        return display;
    }
}
